from main.ioDevs import IO
from main.dataStructures import ProcessesQueue
from main.cpu import CPU
from main.shortTermSchedulers import Scheduler_FirstComeFirstServe, Scheduler_ByPriorities, Scheduler_RoundRobin_E, Scheduler_ShortestJobFirst_NE,Scheduler_ShortestJobFirst_E
from main.longTermSchedulers import LongTermScheduler
from main.expropiationVerificationDevices import Timer
from main.kernel import Kernel
from main.ioDevs import Printer 
from threading import Thread
from time import sleep
from main.memory import Disk , PhysicalMemory, MMU_ContinuousAssignment, BestAdjustment,Pagination_PhysicalMemory,Pagination

#-----------------------------------------------------------------------#
#------------------CLASS OS_FACTORY-------------------------------------#
#-----------------------------------------------------------------------#

class OS(Thread):
    def __init__(self):
        Thread.__init__(self)
        self.memory = PhysicalMemory(50,BestAdjustment())
        self.arrivingProcessesQueue = ProcessesQueue()
        self.readyProcessesQueue = ProcessesQueue()
        self.finishedProcessesQueue = ProcessesQueue()
        self.shortTermScheduler = None
        self.io = IO()
        self.disk = Disk()
        self.cpu = CPU(self.readyProcessesQueue,self.io,self.memory,self.disk)
        self.longTermScheduler = LongTermScheduler(self.arrivingProcessesQueue, self.readyProcessesQueue,'Here the kernel later')
        self.kernel = Kernel(self.longTermScheduler,self.shortTermScheduler,self.cpu,self.arrivingProcessesQueue,self.readyProcessesQueue,self.finishedProcessesQueue,self.memory,self.disk)
        #HACK
        self.cpu.kernel = self.kernel
        self.longTermScheduler.kernel = self.kernel       
        #<PARCHE>
        devicesPatch = []
        devicesPatch.append(Printer(1,self.kernel,self.io.processesUsingADevice))
        devicesPatch.append(Printer(2,self.kernel,self.io.processesUsingADevice))
        self.io.devices = devicesPatch
        #</PARCHE>
        self.power = True
        

    def addNewProcess(self,aProcess):
        #El Kernel lo agrega al lanzar la interrupt
        self.disk.addProcessToDisk(aProcess)                    #Lo agrega al disco
        self.kernel.interrupt_newProcessArrived(aProcess)

#----------------------------------------#
    def run(self):
        self.cpu.start()
        self.io.start()
        self.kernel.start()
        while(self.power):
            sleep(1000)
            
        
class OS_Factory():
     
    @classmethod  
    def newFCFS_OS(cls):
        os = OS()
        os.shortTermScheduler = Scheduler_FirstComeFirstServe(os.readyProcessesQueue,os.cpu,os.io)
        os.kernel.shortTermScheduler = os.shortTermScheduler
        return os
    
    @classmethod  
    def newBP_OS(cls):
        os = OS()
        os.shortTermScheduler = Scheduler_ByPriorities(os.readyProcessesQueue,os.cpu,os.io)
        os.kernel.shortTermScheduler = os.shortTermScheduler
        return os
   
    
    @classmethod  
    def newSJF_NE_OS(cls):
        os = OS()
        os.shortTermScheduler = Scheduler_ShortestJobFirst_NE(os.readyProcessesQueue,os.cpu,os.io)
        os.kernel.shortTermScheduler = os.shortTermScheduler
        return os
    
    
    @classmethod  
    def newSJF_E_OS(cls):
        os = OS()
        os.shortTermScheduler = Scheduler_ShortestJobFirst_E(os.readyProcessesQueue,os.cpu,os.io)
        os.kernel.shortTermScheduler = os.shortTermScheduler
        return os
    
    @classmethod
    def newRR_OS(cls,aTimeQuantum):
        os = OS()
        os.shortTermScheduler = Scheduler_RoundRobin_E(os.readyProcessesQueue,os.cpu,os.io)
        os.kernel.shortTermScheduler = os.shortTermScheduler
        # Un Expropiation Verification Device es o un Timer para el RR o un coso que te dice si hay que expropiar
        # porque entro un proceso mas corto
        os.expropiationVerificationDevice = Timer(aTimeQuantum,os.kernel)
        return os       
    
        
class OS_Pagination(Thread): 
    def __init__(self):
        Thread.__init__(self)
        self.memory = Pagination_PhysicalMemory(50,Pagination(),5)
        self.arrivingProcessesQueue = ProcessesQueue()
        self.readyProcessesQueue = ProcessesQueue()
        self.finishedProcessesQueue = ProcessesQueue()
        self.shortTermScheduler = None
        self.io = IO()
        self.disk = Disk()
        self.cpu = CPU(self.readyProcessesQueue,self.io,self.memory,self.disk)
        self.longTermScheduler = LongTermScheduler(self.arrivingProcessesQueue, self.readyProcessesQueue,'Here the kernel later')
        self.kernel = Kernel(self.longTermScheduler,self.shortTermScheduler,self.cpu,self.arrivingProcessesQueue,self.readyProcessesQueue,self.finishedProcessesQueue,self.memory,self.disk)
        #HACK
        self.cpu.kernel = self.kernel
        self.longTermScheduler.kernel = self.kernel       
        #<PARCHE>
        devicesPatch = []
        devicesPatch.append(Printer(1,self.kernel,self.io.processesUsingADevice))
        devicesPatch.append(Printer(2,self.kernel,self.io.processesUsingADevice))
        self.io.devices = devicesPatch
        #</PARCHE>
        self.power = True
        

    def addNewProcess(self,aProcess):
        #El Kernel lo agrega al lanzar la interrupt
        self.disk.addProcessToDisk(aProcess)                    #Lo agrega al disco
        self.kernel.interrupt_newProcessArrived(aProcess)

#----------------------------------------#
    def run(self):
        self.cpu.start()
        self.io.start()
        self.kernel.start()
        while(self.power):
            sleep(1000)
            
            
class OS_PaginationFactory():
     
    @classmethod  
    def newFCFS_OS(cls):
        os = OS_Pagination()
        os.shortTermScheduler = Scheduler_FirstComeFirstServe(os.readyProcessesQueue,os.cpu,os.io)
        os.kernel.shortTermScheduler = os.shortTermScheduler
        return os
    
    @classmethod  
    def newBP_OS(cls):
        os = OS_Pagination()
        os.shortTermScheduler = Scheduler_ByPriorities(os.readyProcessesQueue,os.cpu,os.io)
        os.kernel.shortTermScheduler = os.shortTermScheduler
        return os
   
    
    @classmethod  
    def newSJF_NE_OS(cls):
        os = OS_Pagination()
        os.shortTermScheduler = Scheduler_ShortestJobFirst_NE(os.readyProcessesQueue,os.cpu,os.io)
        os.kernel.shortTermScheduler = os.shortTermScheduler
        return os
    
    
    @classmethod  
    def newSJF_E_OS(cls):
        os = OS_Pagination()
        os.shortTermScheduler = Scheduler_ShortestJobFirst_E(os.readyProcessesQueue,os.cpu,os.io)
        os.kernel.shortTermScheduler = os.shortTermScheduler
        return os
    
    @classmethod
    def newRR_OS(cls,aTimeQuantum):
        os = OS_Pagination()
        os.shortTermScheduler = Scheduler_RoundRobin_E(os.readyProcessesQueue,os.cpu,os.io)
        os.kernel.shortTermScheduler = os.shortTermScheduler
        # Un Expropiation Verification Device es o un Timer para el RR o un coso que te dice si hay que expropiar
        # porque entro un proceso mas corto
        os.expropiationVerificationDevice = Timer(aTimeQuantum,os.kernel)
        return os  